#include "CommandLine.h"
#include "Application.h"

#include <iostream>
#include <sstream>

using namespace Poco;
using namespace std;

CommandLine::CommandLine()
    : _logger(Logger::get("application.CommandLine")), _exit(false)
{
    _thread.setName("CommandLineThread");
    _thread.start(&CommandLine::threadProcedure, this);

    _logger.information("CommandLineThread started.");
}

CommandLine::~CommandLine()
{
    // 通知线程退出
    _exit = true;

    // 等待线程退出
    _thread.tryJoin(5000);

    _logger.information("CommandLineThread exited.");
}

void CommandLine::threadProcedure(void *pContext)
{
    CommandLine *pCommandLine = static_cast<CommandLine *>(pContext);

    string command;
    while (!pCommandLine->_exit)
    {
        // cout << "percipient-service> ";
        if (!getline(cin, command))
            break;

        pCommandLine->handleCommand(command);
    }
}

const std::map<std::string, void (CommandLine::*)(std::istream &)> CommandLine::_commandTable = {
    {"exit", &CommandLine::handleExitCommand},
    {"quit", &CommandLine::handleExitCommand},
};

void CommandLine::handleCommand(const std::string &command)
{
    if (command.empty())
        return;

    istringstream iss(command);
    string key;
    iss >> key;
    auto entry = _commandTable.find(key);
    if (entry == _commandTable.end())
    {
        cout << key << ": command not found" << endl;
    }
    else
    {
        ((*this).*(entry->second))(iss);
    }
}

void CommandLine::handleExitCommand(std::istream &args)
{
    string arg;
    args >> arg;

    if (arg != "definitely")
    {
        cout << "Type `exit definitely` to exit percipient-service." << endl;
        return;
    }

    Application &application = dynamic_cast<Application &>(Util::Application::instance());
    _exit = true;
    application.terminate();
}
